<?php

namespace admin\model;

use admin\config;

/**
 * 数据库基本对象类
 * 提供数据库底层的 增删查改 功能
 * 本类实现模式：单例模式
 */
class Db{
    //本类的唯一对象
    private static $instance = null;
    //数据库参数
    private $dbConfig = [
        'db'=>'mysql',
        'host'=>'localhost',
        'port'=>'3306',
        'user'=>'root',
        'pass'=>'root',
        'charset'=>'utf8',
        'dbname'=>'blog_system'
    ];
    //数据库的链接
    private $conn = null;

    //新增主键Id
    public $insertId = null;

    //受影响的数目条数
    public $num = 0;

    //预处理数据
    private $datas = null;
    /**
     * 单例模式
     * 构造方法私有化
     * 防止外部构造对象
     */
    private function __construct(){
        //调用方法，链接数据库
        $this->connect();
    }
    //不允许外部克隆
    private function __clone(){}

    /**
     * 获取类对象的方法 
     */
    public static function getInstance(){
        if(!self::$instance instanceof self){
            //     //初始化构造方法的参数
                self::$instance = new self();
            }
         return self::$instance;
    }
    
    /**
     * 链接数据库
     * 链接成功将 conn 进行赋值
     * 链接失败停止并输出错误信息
     */
    private function connect(){
        try{
            //配置数据源 DSN
            $dsn = "{$this->dbConfig['db']}:host={$this->dbConfig['host']};
            port={$this->dbConfig['port']};dbname={$this->dbConfig['dbname']};
            charset={$this->dbConfig['charset']}";
            //创建PDO对象赋值给 conn 
            $this->conn = new \PDO($dsn,$this->dbConfig['user'],$this->dbConfig['pass']);
            //设置客户端的默认字符集
            $this->conn->query("SET NAMES {$this->dbConfig['charset']}");
            $this->conn->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION);    //设置异常模式
        }catch(PDOException $e){
            die('CONNECT ERROR'.$e->getMessage());
        }
    }

    /**
     * 数据库的新增、删除、更新操作
     * 返回受影响的记录条数
     * 如果新增返回最新增数据的id号
     */
    public function exec($sql){
        $this->num = $this->conn->exec($sql);      //执行操作并返回影响条数
        if($this->num>0){
            if($this->conn->lastInsertId() !== null){
                return $this->insertId = $this->conn->lastInsertId();
            }else{
                $error = $this->conn->errorInfo();//获取操作的错误信息
                //[0] 错误标识符 [1] 错误代码 [2]  错误信息
                print 'ERROR'.$error[0].':'.$error[1].':'.$error[2];
            }
        }
    }

    //单条查询
    public function fetch($sql){
        return $this->conn->query($sql)->fetch(\PDO::FETCH_ASSOC);
    }

    //获取多条查询结果
    public function fetchAll($sql){
        return $this->conn->query($sql)->fetchAll(\PDO::FETCH_ASSOC);
    }

    //预处理设置数据
    public function datas($datas){
        $this->datas=$datas;
    }
    //预处理新增、删除、更新操纵
    public function prepare_execute($sql){
        //预处理，$sql-查询语句，$this->datas-参数数据
        $stmt = $this->conn->prepare($sql);
        $stmt->execute($this->datas);
        $this->num = $stmt->rowCount();
        if($this->conn->lastInsertId() !== null){
            return $this->insertId = $this->conn->lastInsertId();
        }else{
            $error = $this->conn->errorInfo();//获取操作的错误信息
            //[0] 错误标识符 [1] 错误代码 [2]  错误信息
            print 'ERROR'.$error[0].':'.$error[1].':'.$error[2];
        }
    }
    public function prepare_fetch($sql){
        //预处理，$sql-查询语句，$this->datas-参数数据
        $stmt=$this->conn->prepare($sql);
        $stmt->execute($this->datas);
        return $stmt->fetch(\PDO::FETCH_ASSOC);
    }
    public function prepare_fetchAll($sql){
        //预处理，$sql-查询语句，$this->datas-参数数据
        $stmt=$this->conn->prepare($sql);
        $stmt->execute($this->datas);
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }
    /**
     * 开启事务
     */
    public function beginTransaction(){
        $this->conn->beginTransaction(); 
    }
    /**
     * 提交事务
     */
    public function commit(){
        $this->conn->commit(); 
    }
    /**
     * 回滚
     */
    public function rollBack(){
        $this->conn->rollBack(); 
    }
}